/*================================================================
*   Copyright (C) 2024 baichao All rights reserved.
*
*   文件名称：sem.c
*   创 建 者：baichao
*   创建日期：2024年03月26日
*   描    述：
*
================================================================*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <unistd.h>

// 定义信号量操作结构体
struct sembuf sem_operation;

int main() {
  // 创建信号量集，包含一个信号量
  int semid = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
  if (semid == -1) {
    perror("semget");
    exit(1);
  }

  // 初始化信号量的值为1
  semctl(semid, 0, SETVAL, 1);

  // Fork子进程
  pid_t pid = fork();
  if (pid == -1) {
    perror("fork");
    exit(1);
  }

  if (pid == 0) {
    // 进入子进程
    // 在临界区之前等待信号量
    sem_operation.sem_num = 0;
    sem_operation.sem_op = -1;  // 减1，等待信号量
    sem_operation.sem_flg = 0;
    semop(semid, &sem_operation, 1);

    // 进入临界区
    printf("Child process is in critical section.\n");
    sleep(2);  // 模拟临界区的操作
    printf("Child process exits critical section.\n");

    // 释放信号量
    sem_operation.sem_op = 1;  // 加1，释放信号量
    semop(semid, &sem_operation, 1);
  } else {
    // 进入父进程
    // 在临界区之前等待信号量
    sem_operation.sem_num = 0;
    sem_operation.sem_op = -1;  // 减1，等待信号量
    sem_operation.sem_flg = 0;
    semop(semid, &sem_operation, 1);

    // 进入临界区
    printf("Parent process is in critical section.\n");
    sleep(2);  // 模拟临界区的操作
    printf("Parent process exits critical section.\n");

    // 释放信号量
    sem_operation.sem_op = 1;  // 加1，释放信号量
    semop(semid, &sem_operation, 1);

    // 等待子进程退出
    wait(NULL);

    // 删除信号量集
    semctl(semid, 0, IPC_RMID);
  }

  return 0;
}